package utils

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"strings"
)

// crc16Modbus计算函数
func crc16Modbus(data []byte) uint16 {
	crc := uint16(0xFFFF)
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if (crc & 0x0001) > 0 {
				crc = (crc >> 1) ^ 0xA001
			} else {
				crc >>= 1
			}
		}
	}
	// 计算得到的是大端序16进制数，modbus协议需要转换成小端序16进制数

	return crc
}

// 返回带大端序crc16校验的字符串
func GenerateWithBigEndianCRC16(input string) (string, error) {
	if len(input)%2 != 0 {
		return "", errors.New("invalid hex string length")
	}

	bytes, err := hex.DecodeString(input)
	if err != nil {
		return "", err
	}

	crc := crc16Modbus(bytes)
	// 转换为大端序
	bytesBigEndian := make([]byte, 2)
	binary.BigEndian.PutUint16(bytesBigEndian, crc)

	return input + strings.ToUpper(hex.EncodeToString(bytesBigEndian)), nil
}

// 返回带小端序crc16校验的字符串
func GenerateWithLittleEndianCRC16(input string) (string, error) {
	if len(input)%2 != 0 {
		return "", errors.New("invalid hex string length")
	}

	bytes, err := hex.DecodeString(input)
	if err != nil {
		return "", err
	}

	crc := crc16Modbus(bytes)
	// 转换为小端序
	bytesLittleEndian := make([]byte, 2)
	binary.LittleEndian.PutUint16(bytesLittleEndian, crc)

	return input + strings.ToUpper(hex.EncodeToString(bytesLittleEndian)), nil
}
